package br.ufrj.dcc.tp.ant;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;

import org.apache.tools.ant.RuntimeConfigurable;
import org.apache.tools.ant.Target;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskContainer;

public class ForTask extends Task implements TaskContainer {
	
	private final String UP_TIME = "up_time", STREAM_INTERVAL = "stream_interval", LINK_CAPACITY = "link_capacity";
	private final String JAVA = "java", EXEC = "exec";
	private final String VALUE = "value", ARG = "arg", DESCRIPTION = "description";
	
	private String algorithm, argument;
	private BigDecimal inferior, superior, step;
	private int scale;
	
	private List<Task> args = null;
	
	public ForTask() {
		super();
		args = new ArrayList<Task>();
	}
	
	@Override
	public void execute() {
//		log("Executando algoritmo " + algorithm + ".");
//		log("De " + inferior + " até " + superior + " com passos de " + step);
//		log("Com argumento = " + argument);
		
		BigDecimal value = BigDecimal.valueOf(inferior.doubleValue());
		HashMap<String, RuntimeConfigurable> execArgs = new HashMap<String, RuntimeConfigurable>();
		HashMap<String, RuntimeConfigurable> javaArgs = new HashMap<String, RuntimeConfigurable>();
		
		Target ns = (Target)getProject().getTargets().get("Executa" + algorithm);
		Task taskExec = null;
		
		for(Task task : ns.getTasks()) {
			if(EXEC.equals(task.getTaskName())) {
				taskExec = task;
				break;
			}
		}
		
		if(taskExec != null) {
			Enumeration<RuntimeConfigurable> en = (Enumeration<RuntimeConfigurable>) taskExec.getRuntimeConfigurableWrapper().getChildren();
			en.nextElement(); // ignora o primeiro...
			en.nextElement(); // ignora o segundo...
			RuntimeConfigurable configuration = null;
			while(en.hasMoreElements()) {
				configuration = en.nextElement();
				execArgs.put(configuration.getAttributeMap().get(DESCRIPTION).toString(), configuration);
			}
		}
		
		Target java = (Target)getProject().getTargets().get("CalculaMetrica" + algorithm);
		Task taskJava = null;
		
		for(Task task : java.getTasks()) {
			if(JAVA.equals(task.getTaskName())) {
				taskJava = task;
				break;
			}
		}
		
		if(taskJava != null) {
			Enumeration<RuntimeConfigurable> en = (Enumeration<RuntimeConfigurable>) taskJava.getRuntimeConfigurableWrapper().getChildren();
			en.nextElement(); // ignora o primeiro...
			RuntimeConfigurable configuration = null;
			while(en.hasMoreElements()) {
				configuration = en.nextElement();
				javaArgs.put(configuration.getAttributeMap().get(DESCRIPTION).toString(), configuration);
			}
		}
		
		
		
		int argumentIndex = 0;
		Hashtable attributeMap = null;
		RuntimeConfigurable configuration = null;
		for(int i = 0; i < args.size(); ++i) {
			
			attributeMap = args.get(i).getRuntimeConfigurableWrapper().getAttributeMap();
			
			configuration = execArgs.get(attributeMap.get(DESCRIPTION));
			
			configuration.setAttribute(VALUE, attributeMap.get(VALUE).toString());
			
			configuration = javaArgs.get(attributeMap.get(DESCRIPTION));
			configuration.setAttribute(VALUE, attributeMap.get(VALUE).toString());
			
			if(argument.equals(attributeMap.get(DESCRIPTION))) {
				argumentIndex = i;
			}
		}
		
		attributeMap = args.get(argumentIndex).getRuntimeConfigurableWrapper().getAttributeMap();
		for(;value.compareTo(superior) < 1; value = value.add(step).setScale(scale, BigDecimal.ROUND_FLOOR)) {
			configuration = execArgs.get(attributeMap.get(DESCRIPTION));
			configuration.setAttribute(VALUE, value.toPlainString());
			
			configuration = javaArgs.get(attributeMap.get(DESCRIPTION));
			configuration.setAttribute(VALUE, value.toPlainString());
			
			ns.execute();
			java.execute();
		}
		
//		for(;value.compareTo(superior) < 1; value = value.add(step)) {
//			
//			value = value.setScale(scale, BigDecimal.ROUND_UP);
//			
//			// Modificando o target java
//			Target target2 = (Target) getProject().getTargets().get("CalculaMetrica" + algorithm);
//			
//			if(target2 != null) {
//				for(Task task : target2.getTasks()) {
//					if(JAVA.equals(task.getTaskName())) {
//						@SuppressWarnings("unchecked")
//						Enumeration<RuntimeConfigurable> en = (Enumeration<RuntimeConfigurable>)task.getRuntimeConfigurableWrapper().getChildren();
//						en.nextElement(); // Ignorando o primeiro arg
//						if(UP_TIME.equals(argument)) {
//							en.nextElement().setAttribute(VALUE, value.toPlainString());
//						} else if(STREAM_INTERVAL.equals(argument)) {
//							en.nextElement(); // Ignorando o segundo argumento
//							en.nextElement().setAttribute(VALUE, value.toPlainString());
//						} else if(LINK_CAPACITY.equals(argument)) {
//							en.nextElement(); // Ignorando o segundo argumento
//							en.nextElement(); // Ignorando o terceiro argumento
//							en.nextElement().setAttribute(VALUE, value.toPlainString());
//						}
//						break;
//					}
//				}
//				
//				Target target1 = (Target) getProject().getTargets().get("Executa" + algorithm);
//				if(target1 != null) {
//					for(Task task : target1.getTasks()) {
//						if(EXEC.equals(task.getTaskName())) {
//							@SuppressWarnings("unchecked")
//							Enumeration<RuntimeConfigurable> en = (Enumeration<RuntimeConfigurable>)task.getRuntimeConfigurableWrapper().getChildren();
//							en.nextElement(); // Ignorando o primeiro arg
//							en.nextElement(); // Ignorando o segundo arg
//							if(UP_TIME.equals(argument)) {
//								en.nextElement().setAttribute(VALUE, value.toPlainString());
//							} else if(STREAM_INTERVAL.equals(argument)) {
//								en.nextElement(); // Ignorando o terceiro argumento
//								en.nextElement().setAttribute(VALUE, value.toPlainString());
//							} else if(LINK_CAPACITY.equals(argument)) {
//								en.nextElement(); // Ignorando o terceiro argumento
//								en.nextElement(); // Ignorando o quarto argumento
//								en.nextElement().setAttribute(VALUE, value.toPlainString());
//							}
//							break;
//						}
//					}
//					
//					// Vou executar:
//					log("Executando Executa" + algorithm + " com " + argument + " = " + value.toPlainString());
//					target1.execute();
//					log("Executando CalculaMetrica" + algorithm + " com " + argument + " = " + value.toPlainString());
//					target2.execute();
//				}
//			}
//		}
	}
	
	public void setScale(int scale) {
		this.scale = scale;
	}
	
	public void addTask(Task task) {
		if(ARG.equals(task.getTaskName())) {
			args.add(task);
		}
	}
	
	public void setInferior(double inferior) {
		this.inferior = new BigDecimal(inferior);
	}
	
	public void setSuperior(double superior) {
		this.superior = new BigDecimal(superior);
	}
	
	public void setStep(double step) {
		this.step = new BigDecimal(step);
	}
	
	public void setAlgorithm(String algorithm) {
		this.algorithm = algorithm;
	}
	
	public void setArgument(String argument) {
		this.argument = argument;
	}
}
